
#include	<system/kernel.h>
#include	<types.h>

#define	PAGE_MAX	1024
#define	PAGE_SIZE	4096
#define	DIR_MAX		PAGE_MAX


static ulong_t*	pagedir = NULL;
static ulong_t*	pagetbl = NULL;
static uint_t		pages_n;	

void	kbasic_paging_setup(int_t root_pgs)
{
	uint_t	dir_n, i;
	int_t	aux;
	ulong_t	addr;
	
	if(!CHECK_FLAG(kbasic_get_flags(), ERR_NO_VARS)) /* variaveis devem estar inicializadas */
		kbasic_skip_main(ERR_NO_VARS);

	pages_n = ((kbasic_get_ex_mem() + 1024) / 4 ); 	/* número de páginas, incluindo diretórios a partir do endereço físico zero. */
	dir_n = (pages_n % 1024) ? (pages_n / 1024) + 1 : (pages_n / 1024);

	pagedir = (ulong_t*)((((kbasic_get_ex_mem() - 4 - (pages_n / 256)) * 1024)) & 0xFFFFF000); 	/* Diretórios de páginas ao fim da memória e com endereço divisivel por 4k */// = MEM_MAX - DIRETORIO - N_PAGINAS
	pagedir = (ulong_t*)physical2virtual(pagedir);	
	pagetbl = (ulong_t*)(pagedir + PAGE_SIZE);	/* Tabela de páginas logo após Diretório */
	bzero(pagedir, PAGE_SIZE+(pages_n*4));

	addr = 0;

	for(i = 0; i < pages_n; i++)
	{
		if(root_pgs > 0)
		{
			pagetbl[i] = addr | 0x3; 
		}
		else
		{
			pagetbl[i] = addr | 0x7;
		}

		addr = addr + PAGE_SIZE;
		root_pgs--;
	}

	aux = dir_n;
	for(i = 0; i < 1024; i++)
		if((aux--) > 0)
			pagedir[i] = ( (ulong_t)virtual2physical(&pagetbl[i*PAGE_MAX]) ) | 3;
		else
			pagedir[i] = 0 | 2;

	write_cr3((ulong_t)virtual2physical(pagedir));
	write_cr0(read_cr0() | 0x80000000);

	kbasic_set_flag(KF_PAGING);

	kprintf("Paging enabled:\n\tDirectory @ 0x%x\n", pagedir);
	kprintf("\tRoot pages -> %d (%dKB)\n", get_root_pages(), get_root_pages()*4);
}

uint_t	get_root_pages()
{
	uint_t	aux = pages_n;
	uint_t	ret = 0;
	while(aux--)
	{
		if(!(pagetbl[aux] & 0x4))
			ret++;
	}
	return ret;		
}

